package com.example.meservice.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.meservice.domain.dto.rechargeDTO;
import com.example.meservice.domain.entity.User;
import com.example.meservice.domain.entity.coupon;
import com.example.meservice.service.IMeService;
import com.example.meservice.utils.CurrentHoler;
import com.example.meservice.utils.JwtUtil;
import com.example.meservice.utils.Result;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 用户个人中心控制器
 * 提供用户信息管理、登录、充值、优惠券和签到等功能
 *
 * @author czwa
 */
@RestController
@RequestMapping("/me")
public class meController {

    @Autowired
    private IMeService meService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 获取当前用户信息
     *
     * @return 用户信息
     */
    @GetMapping
    public Result getMe() {
        return Result.success(meService.getMe());
    }

    /**
     * 用户登录
     * 验证手机号格式并生成JWT令牌
     *
     * @param user 包含手机号和密码的用户对象
     * @return JWT令牌
     */
    @PostMapping("/login")
    public Result login(@RequestBody User user) {
        // 校验手机号格式
        if (!isValidPhoneNumber(user.getPhone())) {
            throw new RuntimeException("手机号格式错误");
        }

        // 验证用户并获取信息
        User me = meService.login(user);
        if (me == null || me.getStatus() == 0) {
            throw new RuntimeException("您的账号不存在或已被禁用");
        }

        // 生成JWT令牌并缓存到Redis
        String token = JwtUtil.generateJwt("id", me.getId());
        stringRedisTemplate.opsForValue()
                .set("user:" + user.getId(), token, 15, TimeUnit.of(ChronoUnit.MINUTES));

        return Result.success(token);
    }

    /**
     * 验证手机号格式
     *
     * @param phoneNumber 手机号
     * @return 格式是否正确
     */
    private boolean isValidPhoneNumber(String phoneNumber) {
        String regex = "^1[3-9]\\d{9}$";
        return phoneNumber.matches(regex);
    }

    /**
     * 用户充值
     * 增加用户余额并记录充值订单
     *
     * @param rechargeDTO 充值金额信息
     * @return 操作结果
     */
    @PutMapping("/recharge")
    public Result recharge(@RequestBody rechargeDTO rechargeDTO) {
        // 更新用户余额
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", CurrentHoler.getCurrentId())
                .setSql("balance=balance+" + rechargeDTO.getAmount());
        meService.update(updateWrapper);

        // 记录充值订单
        meService.addRechargeOrder(rechargeDTO.getAmount());

        return Result.success();
    }

    /**
     * 获取充值订单记录
     *
     * @return 充值订单列表
     */
    @GetMapping("/recharge")
    public Result getRechargeOrder() {
        return Result.success(meService.getRechargeOrder());
    }

    /**
     * 获取用户个人信息
     * 仅返回敏感字段
     *
     * @return 用户个人信息
     */
    @GetMapping("/information")
    public Result getInformation() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("username", "password", "gender", "phone", "image")
                .eq("id", CurrentHoler.getCurrentId());
        return Result.success(meService.getOne(queryWrapper));
    }

    /**
     * 更新用户信息
     *
     * @param user 包含要更新信息的用户对象
     * @return 操作结果
     */
    @PutMapping("/update")
    public Result update(@RequestBody User user) {
        user.setId(CurrentHoler.getCurrentId());
        meService.updateInformationById(user);
        return Result.success();
    }

    /**
     * 获取用户优惠券数量
     *
     * @return 优惠券数量
     */
    @GetMapping("/count")
    public Result getCouponCount() {
        Integer count = meService.getCouponCount();
        return Result.success(count);
    }

    /**
     * 获取用户优惠券列表
     *
     * @return 优惠券列表
     */
    @GetMapping("/coupon")
    public Result getMyCoupon() {
        List<coupon> coupons = meService.getMyCoupon();
        return Result.success(coupons);
    }

    /**
     * 用户签到
     * 使用Redis BitMap记录签到状态并计算连续签到天数
     *
     * @return 操作结果
     */
    @PostMapping("/sign")
    public Result sign() {
        Integer userId = CurrentHoler.getCurrentId();
        LocalDateTime now = LocalDateTime.now();

        // 构建Redis键（格式：sign:用户ID:年月）
        String keyPre = now.format(DateTimeFormatter.ofPattern("yyyyMM"));
        String key = "sign:" + userId + ":" + keyPre;
        int dayOfMonth = now.getDayOfMonth();

        // 检查是否已签到
        if (Boolean.TRUE.equals(stringRedisTemplate.opsForValue().getBit(key, dayOfMonth - 1))) {
            return Result.error("今天已经签到过了");
        }

        // 记录签到
        stringRedisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);

        // 计算连续签到天数
        List<Long> result = stringRedisTemplate.opsForValue().bitField(
                key,
                BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0)
        );

        if (result == null || result.isEmpty()) {
            return Result.success(0);
        }

        Long num = result.get(0);
        if (num == null) {
            return Result.success(0);
        }

        int count = 0;
        while (true) {
            if ((num & 1) == 0) {
                break;
            } else {
                count++;
                num >>>= 1;
            }
        }

        // 更新用户经验和积分
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", userId)
                .setSql("exp=exp+" + count + ",point=point+" + count);
        meService.update(updateWrapper);

        // 检查并更新用户等级
        meService.checkAndUpdate(CurrentHoler.getCurrentId());

        return Result.success();
    }

    /**
     * 获取用户连续签到天数
     *
     * @return 连续签到天数
     */
    @GetMapping("/sign")
    public Result getSign() {
        Integer userId = CurrentHoler.getCurrentId();
        LocalDateTime now = LocalDateTime.now();

        // 构建Redis键（格式：sign:用户ID:年月）
        String keyPre = now.format(DateTimeFormatter.ofPattern("yyyyMM"));
        String key = "sign:" + userId + ":" + keyPre;
        int dayOfMonth = now.getDayOfMonth();

        // 获取签到记录并计算连续天数
        List<Long> result = stringRedisTemplate.opsForValue().bitField(
                key,
                BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0)
        );

        if (result == null || result.isEmpty()) {
            return Result.success(0);
        }

        Long num = result.get(0);
        if (num == null) {
            return Result.success(0);
        }

        int count = 0;
        while (true) {
            if ((num & 1) == 0) {
                break;
            } else {
                count++;
                num >>>= 1;
            }
        }

        return Result.success(count);
    }
}